package world;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.NoSuchElementException;

import be.kuleuven.cs.som.annotate.*;
import world.placement.Position;
import world.square.*;


/**
 * A class representing a level (plateau).
 * @param 	<S>
 * 			The type parameter, which is a square.
 * 
 * @author Wim Marynissen, Frederic Mes
 * @version 1.0
 */
public class Level<S extends Square> extends Dungeon<S>{
	
	/**
	 * Creates a new level with the specified maximum dimensions. It's a dungeon with only x and y coordinates.
	 * @param 	xMaxCoord
	 * 		  	The maximum size this dungeon has in the x-direction
	 * @param 	yMaxCoord
     * 		  	The maximum size this dungeon has in the y-direction
     * @effect 	This new level is initialized as a dungeon with given coordinates as the maximum coordinates.
	 *          | super(xMaxCoord, yMaxCoord, 0)
	 * @post	The fixed position is set equal to the origin.
	 * 			| new.getFixedPosition() == new Position(0, 0, 0)
	 */
	public Level (long xMaxCoord, long yMaxCoord){
		super (xMaxCoord, yMaxCoord, 0);
		setFixedPosition(new Position(0, 0, 0));
	}
	
	/**
	 * Returns whether or not this level can have a given position as its new position.
	 * @param 	position
	 * 		  	The position to be checked.
	 * @return 	Returns false if the given z-coordinate is not equal to 0.
	 * 		   	| if (position.getZCoord() != 0)
	 * 		   	|  	then result == false
	 * @return 	Check if the position is valid for this dungeon.
	 * 			| result == super.canHaveAsPosition(position)
	 */
	@Override
	public boolean canHaveAsPosition (Position position){
		if (position.getZCoord() != 0)
			return false;
		return (super.canHaveAsPosition(position));
	}

	/**
	 * Returns the dungeon which contains this dungeon
	 */
	@Override @Basic
	public Composite<S> getContainingDungeon() {
		return containingDungeon;
	}

	/**
	 * Returns the rootdungeon of this dungeon.
	 */
	@Override
	public Dungeon<S> getRootDungeon() {
		if (getContainingDungeon() == null)
			return this;
		return getContainingDungeon().getRootDungeon();
	}

		
	/**
	 * Sets the the containing dungeon to the given value.
	 */
	@Override
	public void setContainingDungeon(Composite<S> dungeon) {
		this.containingDungeon = dungeon;	
	}
	
	/**
	 * Variable registering the containing dungeon. Standard value is null.
	 */
	private Composite<S> containingDungeon;

	
	/**
	 * Return an iterator returning all the elements in this 
	 * level dungeon.
	 */
	@Override
	public Iterator<S> iterator() {
		return new Iterator<S>() {

			private Iterator<S> currentIterator = getSquares().keySet().iterator();

			public boolean hasNext() {
				return currentIterator.hasNext();
			}

			public S next() throws NoSuchElementException {
				if (!hasNext())
					throw new NoSuchElementException();
				return currentIterator.next();
			}

			public void remove() throws UnsupportedOperationException {
				throw new UnsupportedOperationException();
			}
		};
	}

	/**
	 * A method returning all the possible positions that can exist in this level.
	 * 
	 * @return	An arraylist of positions.
	 * 			| let 
	 * 			|	i = 0, j = 0
	 * 			| in 
	 *  		| 	for i <= getMaxXCoord,i++:
	 *  		|		for j <= getMaxYCoord,j++:
	 *  		| 			result.contains(new Position (i, j, 0)
	 */
	@Override
	public ArrayList<Position> getAllPossiblePositions() {
		ArrayList<Position> positions = new ArrayList<Position>();
		for (long i = 0; i <= getMaxXCoord(); i++) {
			for (long j = 0; j <= getMaxYCoord(); j++) {
				positions.add(new Position(i, j, 0));
			}
		}
		return positions;
	}	
	
	/**
	 * @param 	maxZCoord
	 * 			The maximum size this dungeon has in the z-direction
	 * @throws	UnsupportedOperationException
	 * 			The maximum z coordinate of a level can't be changed.
	 */
    @Override
    public void setMaxZCoord(long maxZCoord) throws UnsupportedOperationException{
    		throw new UnsupportedOperationException("The z coordinate of a level can't change.");

    }
}

